package main

import (
	"bytes"
	"encoding/binary"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"
	"sync"
	"unsafe"
)

type TaskList []TaskInfo

var logger = log.Logger{}

type Result struct {
	Msg  string
	Code int
	Data interface{}
}

type TaskInfo struct {
	Name string
}

var handleTaskCh chan TaskInfo = make(chan TaskInfo)
var quitCh chan bool = make(chan bool)
var taskListStore TaskList = make(TaskList, 0)

func main() {
	logger.SetPrefix("[task]")
	logger.SetOutput(os.Stdout)
	logger.SetFlags(log.LstdFlags)
	// https://api.github.com/meta
	// go handleTask(handleTaskCh, quitCh)
	// listenServer()
	ip := "185.199.108.0/22"
	ip = "140.82.112.0/20"
	lastNIndex := strings.LastIndex(ip, "/")
	mastWidth, _ := strconv.Atoi(ip[lastNIndex+1:])
	stringIp := ip[0:lastNIndex]
	logger.Println("s=", mastWidth, "ipString=", stringIp)

	ipuint32 := StringIpToInt32(stringIp)
	logger.Printf("ipb = %b", ipuint32)
	ipInt := *(*int)(unsafe.Pointer(&ipuint32))
	logger.Println("IP int=", ipInt)

	ipStr := IpIntToString(ipInt)
	logger.Println("IP str=", ipStr)

	i2 := getMask()
	diff := 32 - mastWidth
	i2 = i2 << diff
	ipuint32 = ipuint32 & i2
	logger.Printf("mask int value %d", ipuint32)
	ipInt = *(*int)(unsafe.Pointer(&ipuint32))
	ipStr = IpIntToString(ipInt)

	startIpInt := ipuint32 + 1
	logger.Printf("start ip %s", IpUint32ToString(startIpInt))

	// 22
	logger.Printf("ipb = %b, %s", ipuint32, ipStr)
}

func IpUint32ToString(ip uint32) string {
	ipInt := *(*int)(unsafe.Pointer(&ip))
	ipStr := IpIntToString(ipInt)
	return ipStr
}

func getMask() uint32 {
	var v int = 0
	var pos = 24
	for i := 1; i <= 4; i++ {
		tmp := 255 << pos
		v = tmp | v
		pos -= 8
	}
	int32 := *(*uint32)(unsafe.Pointer(&v))
	return int32
}

func StringIpToUint(ip string) []byte {
	log.Println("IP:", ip)
	var ret int = 0
	ipSegs := strings.Split(ip, ".")
	var pos uint = 24
	for _, seg := range ipSegs {
		v, _ := strconv.Atoi(seg)
		v = v << pos
		ret = ret | v
		// log.Println("ip seg=", seg, v, ret)
		pos -= 8
	}
	// fmt.Printf("int value = %d\n", ret)
	// b := make([]byte, 4)
	int32 := *(*int32)(unsafe.Pointer(&ret))
	b := Int64ToBytes(int32)
	// binary.BigEndian.PutUint32(b, ret)
	return b
}

func StringIpToInt32(ip string) uint32 {
	log.Println("IP:", ip)
	var ret int = 0
	ipSegs := strings.Split(ip, ".")
	var pos uint = 24
	for _, seg := range ipSegs {
		v, _ := strconv.Atoi(seg)
		v = v << pos
		ret = ret | v
		// log.Println("ip seg=", seg, v, ret)
		pos -= 8
	}
	return *(*uint32)(unsafe.Pointer(&ret))
}

func IpIntToString(ipInt int) string {
	ipSegs := make([]string, 4)
	var len int = len(ipSegs)
	buffer := bytes.NewBufferString("")
	for i := 0; i < len; i++ {
		tempInt := ipInt & 0xFF
		ipSegs[len-i-1] = strconv.Itoa(tempInt)
		ipInt = ipInt >> 8
	}
	for i := 0; i < len; i++ {
		buffer.WriteString(ipSegs[i])
		if i < len-1 {
			buffer.WriteString(".")
		}
	}
	return buffer.String()
}

func Int64ToBytes(num int32) []uint8 {
	var buffer bytes.Buffer
	err := binary.Write(&buffer, binary.BigEndian, num)
	if err != nil {
		logger.Fatal(err)
	}
	return buffer.Bytes()
}

func handleTask(taskCh chan TaskInfo, quitCh chan bool) {
	for {
		select {
		case taskInfo := <-taskCh:
			taskListStore = append(taskListStore, taskInfo)
			log.Printf("接收到Task: %+#v", taskInfo)
		case <-quitCh:
			log.Println("退出处理")
			return
		}
	}
}

func getTaskList() TaskList {
	return taskListStore
}

func Success(msg string) Result {
	return Result{Msg: msg, Code: 200}
}

func Json(data interface{}) []byte {
	b, _ := json.Marshal(data)
	return b
}

type GithubMeta struct {
	Web []string `json:"web"`
}

var wg sync.WaitGroup

func resolveIPList(ip string) {
	log.Println("IP:", ip)
	wg.Done()
}

func listenServer() {
	http.HandleFunc("/get-all-tasks", func(resp http.ResponseWriter, req *http.Request) {
		json, _ := json.Marshal(Result{Msg: "操作成功", Code: 200, Data: getTaskList()})
		resp.Header().Add("content-type", "application/json;charset=utf-8")
		resp.Write([]byte(json))
	})

	http.HandleFunc("/github-meta", func(rw http.ResponseWriter, r *http.Request) {
		api := "https://api.github.com/meta"
		r2, err := http.Get(api)
		if err != nil {
			rw.Write([]byte("请求异常"))
			return
		}
		b, err2 := ioutil.ReadAll(r2.Body)
		if err2 != nil {
			rw.Write([]byte("读取异常"))
			return
		}
		githubMeta := GithubMeta{}
		err3 := json.Unmarshal(b, &githubMeta)
		if err3 != nil {
			rw.Write([]byte("转换json异常"))
		}
		fmt.Printf("%#v", githubMeta)

		webJson, err4 := json.Marshal(githubMeta)
		if err4 != nil {
			rw.Write([]byte("JSON序列化异常"))
			return
		}

		for _, str := range githubMeta.Web {
			wg.Add(1)
			resolveIPList(str)
		}

		wg.Wait()

		rw.Write(webJson)
	})

	http.HandleFunc("/add-task", func(rw http.ResponseWriter, r *http.Request) {
		s := r.URL.Query().Get("name")
		taskInfo := TaskInfo{Name: s}
		handleTaskCh <- taskInfo
		rw.Write(Json(Success("完成!")))
	})

	http.ListenAndServe(":9090", nil)
}
